package de.tum.in.far.threedui.general;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Enumeration;
import java.util.Vector;

import javax.media.j3d.Appearance;
import javax.media.j3d.Behavior;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Material;
import javax.media.j3d.Node;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.WakeupCondition;
import javax.media.j3d.WakeupCriterion;
import javax.media.j3d.WakeupOnCollisionEntry;
import javax.media.j3d.WakeupOnCollisionExit;
import javax.media.j3d.WakeupOr;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3f;

import com.sun.j3d.utils.geometry.Cone;
import com.sun.j3d.utils.geometry.Cylinder;



public class PickerArrow extends BranchGroup{
	float length, radius;
	Cylinder cylinder;
	Cone cone;
	Vector<ActionListener> listeners;
	Node collidingObject;
	
	class PickerArrowController extends Behavior
	{

		WakeupCondition condition;
		@Override
		public void initialize() {
			
			System.out.println("ARROW CONTROLLER INSTANTIATED !!");
			// TODO Auto-generated method stub
			setSchedulingBounds(new BoundingSphere(new Point3d(0,0,0), 1));
			
			condition = new WakeupOr(new WakeupCriterion[]{new WakeupOnCollisionEntry(PickerArrow.this), new WakeupOnCollisionExit(PickerArrow.this)});
			wakeupOn(condition);
		}

		@Override
		public void processStimulus(Enumeration arg0) {
			System.out.println("COLLISION DETECTD !!!!");
			
			WakeupCriterion crit = (WakeupCriterion) arg0.nextElement();
			
			if(crit instanceof WakeupOnCollisionEntry)
			{
				WakeupOnCollisionEntry woc = (WakeupOnCollisionEntry) crit;
				Node triggeingObject = woc.getTriggeringPath().getObject();
//				triggeingObject.getBounds().
				if( triggeingObject != PickerArrow.this.cylinder)
				{
				System.out.println("COLLISION IN :[" + ((WakeupOnCollisionEntry) crit).getTriggeringPath().getObject().getClass().getName() + "]");
				ActionEvent event = new ActionEvent(triggeingObject, 0, null);
				for( ActionListener e: PickerArrow.this.listeners)
				{
					e.actionPerformed(event);
				}
				PickerArrow.this.setArrowColor(0.7f, 1, 0.7f);
				PickerArrow.this.collidingObject = triggeingObject;
				}
			}
			else if( crit instanceof WakeupOnCollisionExit)
			{
				WakeupOnCollisionExit woc = (WakeupOnCollisionExit) crit;
				ActionEvent event = new ActionEvent(woc.getTriggeringPath().getObject(), 1, null);
				for( ActionListener e: PickerArrow.this.listeners)
				{
					e.actionPerformed(event);
				}
//				System.out.println("COLLISION OUT :[" + ((WakeupOnCollisionExit) crit).getTriggeringPath().getObject().getClass().getName() + "]");
//				((WakeupOnCollisionExit) crit).getTriggeringPath().getObject();
				PickerArrow.this.setArrowColor(1f, .7f, 0.7f);
				PickerArrow.this.collidingObject = null;
			}
			else
			{
				System.out.println("COLLISION EVENT :" + crit.getClass().getName());
			}
			
			wakeupOn(condition);
			
		}
		
	}
	public PickerArrow(float length, float radius) {
		this.collidingObject = null;
		this.listeners = new Vector<ActionListener>();
		this.length = length;
		this.radius = radius;
		
		cylinder = new Cylinder(radius * 0.7f, 1.2f * length);
		cylinder.setCapability(Cylinder.ENABLE_APPEARANCE_MODIFY);
		cylinder.getAppearance().setCapability(Appearance.ALLOW_MATERIAL_WRITE);
//		cylinder.setCapability(Cylinder.ALLOW_CHILDREN_WRITE);
//		cylinder.setCapability(Cylinder.ALLOW_CHILDREN_EXTEND);
		
		Transform3D cylinderT3D = new Transform3D();
		cylinderT3D.setTranslation(new Vector3f(0, - .6f * length, 0.5f * radius));
		TransformGroup cylinderTG = new TransformGroup(cylinderT3D);
		cylinderTG.addChild(cylinder);
		
		cone = new Cone(radius, 0.8f * length);
		cone.setCapability(Cone.ENABLE_APPEARANCE_MODIFY);
		cone.getAppearance().setCapability(Appearance.ALLOW_MATERIAL_WRITE);
//		cone.setCapability(Cylinder.ALLOW_CHILDREN_WRITE);
//		cone.setCapability(Cylinder.ALLOW_CHILDREN_EXTEND);
//		
		Transform3D coneT3D = new Transform3D();
		coneT3D.setTranslation(new Vector3f(0,  0.4f * length, 0.5f*radius));
		TransformGroup coneTG = new TransformGroup(coneT3D);
		coneTG.addChild(cone);
		

		
		addChild(coneTG);
		addChild(cylinderTG);
//		addChild(new CoordinatesMarker());
		
		setCapability(ALLOW_COLLISION_BOUNDS_READ);
		setCapability(ALLOW_PICKABLE_READ);
		setCapability(ALLOW_PICKABLE_WRITE);
		setCapability(ALLOW_COLLIDABLE_WRITE);
		setCapability(ENABLE_COLLISION_REPORTING);
		setCapability(ENABLE_PICK_REPORTING);
		setCapability(ALLOW_CHILDREN_WRITE);
		setCapability(ALLOW_CHILDREN_READ);
		setCapability(ALLOW_CHILDREN_EXTEND);
		
		addChild(new PickerArrowController());
	}
	
	public Node getCollidingObject()
	{
		return this.collidingObject;
	}
	
	public boolean isColliding()
	{
		return this.collidingObject != null;
	}
	
	public void setAppearance(Appearance app)
	{
		cone.getAppearance().setMaterial(app.getMaterial());
		cylinder.getAppearance().setMaterial(app.getMaterial());
//		cone.setAppearance(app);
//		cylinder.setAppearance(app);
	}
	
	void setArrowColor(float r, float g, float b)
	{
		Material m = new Material();
		m.setAmbientColor(new Color3f(r * 0.7f, g * 0.7f, b * 0.7f));
		m.setDiffuseColor(new Color3f(r,g,b));
		
		Appearance a = new Appearance();
//		a.setCapability(Appearance.)
		a.setMaterial(m);
		setAppearance(a);
	}
	
	public void registerListener(ActionListener l)
	{
		this.listeners.add(l);
	}
}
